﻿using ArtMath.Attribute;
using ArtMath.Component.Line;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Parameter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ArtMath.Component.Circle
{
    /// <summary>
    /// 曲率圆
    /// </summary>
    public class CurvatureCircle : ConstructedCircleBase
    {
        public CurvatureCircle(SketchPad pad, string name, Function func, bool addToList = true) : base(pad, name, func, ToolTypeName.qly, addToList)
        {
            InPoints = new PointBase[1];
        }
        [MultilingualDisplayName("Function")]
        public override LineBase Line { get => base.Line; set => base.Line = value; }
        [MultilingualCategory("Structure"), MultilingualDisplayName("TangentPoint")]
        public PointBase TangentPoint
        {
            get { return InPoints[0]; }
            set { SetPoint(0, value); }
        }
        public override PointD NewCenter
        {
            get
            {
                if (newCenter == null)
                {
                    Function func = Line as Function;
                    if (func != null)
                    {
                        double y1, y2;
                        double? tmp = func.GetTangentLineSlope(TangentPoint.ToPointD());
                        if (tmp.HasValue)
                        {
                            y1 = tmp.Value;
                            Derivation der = new Derivation(func.FirstDerivative, func.IndependentVariable);
                            string f2 = der.GetDerivation();
                            func.FunctionExpression.ForEachRelatedParameter((BasicParameter p) =>
                            {
                                f2 = Regex.Replace(f2, $"\\b{p.Name}\\b", $"({p.Value.Value})");
                                return true;
                            });
                            if (Calculation.Calculate(Regex.Replace(f2, $"\\b{func.IndependentVariable}\\b", $"({(func.IndependentVariable == "x" || func.IndependentVariable == "ρ" ? TangentPoint.X.Value : TangentPoint.Y.Value)})"), out y2))
                            {
                                double com = (1 + y1 * y1) / y2;
                                newCenter = new PointD(TangentPoint.X.Value - y1 * com, TangentPoint.Y.Value + com);
                            }
                        }
                    }
                }
                return newCenter.Value;
            }
        }
        public override PointD NewPCenter
        {
            get
            {
                if (newPcenter == null)
                {
                    newPcenter = Pad.XYToPxy(NewCenter);
                }
                return newPcenter.Value;
            }
        }
        public override double NewRadius
        {
            get
            {
                if (newRadius == null)
                {
                    Function func = Line as Function;
                    if (func != null)
                    {
                        double y1, y2;
                        double? tmp = func.GetTangentLineSlope(TangentPoint.ToPointD());
                        if (tmp.HasValue)
                        {
                            y1 = tmp.Value;
                            Derivation der = new Derivation(func.FirstDerivative, func.IndependentVariable);
                            string f2 = der.GetDerivation();
                            func.FunctionExpression.ForEachRelatedParameter((BasicParameter p) =>
                            {
                                f2 = Regex.Replace(f2, $"\\b{p.Name}\\b", $"({p.Value.Value})");
                                return true;
                            });
                            if (Calculation.Calculate(Regex.Replace(f2, $"\\b{func.IndependentVariable}\\b", $"({(func.IndependentVariable == "x" || func.IndependentVariable == "ρ" ? TangentPoint.X.Value : TangentPoint.Y.Value)})"), out y2))
                            {
                                newRadius = Math.Pow(1 + y1 * y1, 1.5) / Math.Abs(y2);
                            }
                        }
                    }
                }
                return newRadius.Value;
            }
        }
        public override void ComponentChanged(ShapeBase component)
        {
            newCenter = null;
            newPcenter = null;
            newRadius = null;
            base.ComponentChanged(component);
        }
        public override void CreateComponents()
        {
            if (TangentPoint == null)
            {
                TangentPoint = Pad.CreatePoint(Line.OfTranslator("TangentPoint"), SpareCoordinate_);
                base.CreateComponents();
            }
        }
    }
}
